/**
 **oj/javascript - Javascript operations
 * 
 * The javascript module contains a number of useful functions for
 * working with the language.
 *
 */

define([], function() {
    'use strict';
    
    window['javascript'] = {};
    
    
    var KEYWORDS = new RegExp('[ \.();\'"]+(' +
            ['break', 'case', 'catch', 'continue', 'debugger',
             'default', 'delete', 'do', 'else', 'finally', 'for',
             'function', 'if', 'in', 'instanceof', 'new', 'return',
             'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
             'while', 'with', 'undefined', 'null', 'true', 'false'].join('|') + ')[ \.();\'"]+',
             'g'),
        PUNCTUATION = /[\.\(\)\?\*\+,\[\]{};+-]+/g,
        STRING = /'[^']*'|"[^"]*"/g;
    
    
    javascript['tokens'] = function(string) {
        /**
         *> javascript.tokens('string')
         * 
         * Returns an array of tokens from string
         */
        
        var result = [];          // holds token results
        var i = 0;                // index of current character
        var c = string.charAt(i); // current character
        var value;                // token value
        var q;                    // quote character
        var keywords = [
            'break', 'case', 'catch', 'continue', 'debugger',
            'default', 'delete', 'do', 'else', 'finally', 'for',
            'function', 'if', 'in', 'instanceof', 'new', 'return',
            'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
            'while', 'with', 'undefined', 'null', 'true', 'false'
        ];
        
        var until = function (r) {
            for (;;) {
                c = string.charAt(++i);
                if (!c || c === r) {
                    break;
                }
                value += c;
            }
        };
        
        var upto = function (r) {
            for (;;) {
                c = string.charAt(++i);
                if (!c) {
                    break;
                }
                value += c;
                if (r.test(value)) {
                    c = string.charAt(++i);
                    break;
                }
            }
        };
        
        var still = function (r) {
            for (;;) {
                c = string.charAt(++i);
                if (c !== r) {
                    break;
                }
                value += c;
            }
        };
        
        while (c) {
            if (c === ' ') {
                // space
                value = c;
                still(' ');
                result.push({type: 1, value: value});
            } else if (c === '\n') {
                // line break
                value = c;
                still('\n');
                result.push({type: 2, value: value});
            } else if (c === '/' && string.charAt(i + 1) === '/') {
                // line comment
                value = c;
                until('\n');
                result.push({type: 3, value: value});
            } else if (c === '/' && string.charAt(i + 1) === '*') {
                // multiline comment
                value = c;
                upto(/\*\/$/);
                result.push({type: 3, value: value});
            } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '$' || c === '_') {
                // name or keyword
                value = c;
                for (;;) {
                    c = string.charAt(++i);
                    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '$' || c === '_') {
                        value += c;
                    } else {
                        break;
                    }
                }
                
                if (keywords.indexOf(value) > -1) {
                    // keyword
                    result.push({type: 4, value: value});
                } else {
                    // name
                    result.push({type: 5, value: value});
                }
            } else if (c >= '0' && c <= '9') {
                // number
                value = c;
                for (;;) {
                    c = string.charAt(++i);
                    if ((c >= '0' && c <= '9') || c === '.') {
                        value += c;
                    } else {
                        break;
                    }
                }
                result.push({type: 6, value: value});
            } else if (c === '\'' || c === '"') {
                // string
                value = c;
                q = c;
                for (;;) {
                    c = string.charAt(++i);
                    if (!c || c === '\n') {
                        break;
                    }
                    value += c;
                    if (c === '\\') {
                        c = string.charAt(++i);
                        value += c;
                    } else if (c === q) {
                        c = string.charAt(++i);
                        break;
                    }
                }
                result.push({type: 7, value: value});
            } else {
                // operator
                result.push({type: 0, value: c});
                c = string.charAt(++i);
            }
        }
        
        return result;
    };
    
    
    javascript['highlight'] = function(string) {
        /**
         *> javascript.highlight('string')
         *
         * Returns string with syntax highlight spans.
         *
         */
        
        string = string.replace(STRING, '<span class="javascript_string">$&</span>');
        string = string.replace(KEYWORDS, '<span class="javascript_keyword">$&</span>');
        string = string.replace(PUNCTUATION, '<span class="javascript_punctuation">$&</span>');
        
        return string;
    };
    
    
    oj.element(document.head, 'style', {'type': 'text/css'}, [
        '.javascript_punctuation {',
        '  color: #999999;',
        '}',
        '.javascript_string {',
        '  color: #0086FF;',
        '}',
        '.javascript_keyword {',
        '  color: #FB5F22;',
        '}'
    ]);
    
    return javascript;
    
});